package com.heima.behavior.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.behavior.service.BehaviorService;
import com.heima.common.constants.message.ArticleBehaviorRedisPrefixConstants;
import com.heima.common.constants.message.BehaviorConstants;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.threadlocal.UserThreadLocalUtils;
import com.heima.common.util.JsonUtils;
import com.heima.model.behavior.dtos.ArticleBehaviorShowDTO;
import com.heima.model.behavior.dtos.LikesBehaviorDto;
import com.heima.model.behavior.dtos.ReadBehaviorDto;
import com.heima.model.behavior.dtos.UnLikesBehaviorDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class BehaviorServiceImpl implements BehaviorService {

    @Autowired
    StringRedisTemplate redisTemplate;

    /**
     * 文章查看次数统计
     *
     * @param dto
     * @return
     */
    @Override
    public void readBehavior(ReadBehaviorDto dto) {
        // 参数校验
        if (dto == null || dto.getArticleId() == null) {
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 获取到当前登录用户
        Integer userId = UserThreadLocalUtils.getUserIdAndCheckLogin();
        if (userId <= 0) {
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN);
        }

        // 设置redis的key
        String key = BehaviorConstants.BEHAVIOR_READ_PREFIX + ":" + userId;


        // 尝试从redis中获取文章数据
        String json = (String) redisTemplate.opsForHash().get(key, dto.getArticleId() + "");
        // 如果数据不为空, 则累加
        if (StringUtils.isNotEmpty(json) && JsonUtils.toBean(json, ReadBehaviorDto.class) != null) {
            ReadBehaviorDto readBehaviorDto = JsonUtils.toBean(json, ReadBehaviorDto.class);
            readBehaviorDto.setCount(dto.getCount() + readBehaviorDto.getCount());
            redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JSON.toJSONString(readBehaviorDto));
            return;
        }
        // 如果json为空或json解析不出数据, 则新增
        redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JSON.toJSONString(dto));
    }

    /**
     * 不喜欢或者取消不喜欢
     *
     * @param dto
     * @return
     */
    @Override
    public void unlikesBehavior(UnLikesBehaviorDto dto) {
        // 参数校验
        if (dto == null || dto.getArticleId() == null) {
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 判断是否是登录状态
        Integer userId = UserThreadLocalUtils.getUserIdAndCheckLogin();
        if (userId <= 0) {
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN);
        }
        // 保存或删除UnLike信息
        this.saveOrDeleteUnLike(dto);
        // 保存或删除UnLike展示信息
        this.saveOrUpdateUnLikeShow(dto, userId);
    }

    /**
     * 用户点赞或取消点赞
     *
     * @param dto
     */
    @Override
    public void likesBehavior(LikesBehaviorDto dto) {
        Integer userId = UserThreadLocalUtils.getUserIdAndCheckLogin();
        if (userId <= 0) {
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN);
        }

        // 新增或删除点赞信息
        this.saveOrDeleteLike(dto, userId);
        // 新增或修改点赞展示信息
        this.saveOrUpdateLikeShow(dto, userId);
    }
    /**
     * 新增或修改点赞展示信息
     *
     * @param dto
     * @param userId
     */
    private void saveOrUpdateLikeShow(LikesBehaviorDto dto, Integer userId) {
        String key = ArticleBehaviorRedisPrefixConstants.BEHAVIOR_SHOW_PREFIX + ":" + userId;
        ArticleBehaviorShowDTO showDTO = this.getArticleBehaviorShowDTOByArticleId(key, dto.getArticleId());
        if (dto.getOperation() == 0) {
            showDTO.setIslike(true);
            showDTO.setIsunlike(false);
        } else {
            showDTO.setIslike(false);
        }
        redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JSON.toJSONString(showDTO));
    }

    /**
     * 根据ArticleId 从Redis中获取 ArticleBehaviorShowDTO, 如果Redis中不存在, 则会返回一个新的ArticleBehaviorShowDTO
     *
     * @param articleId
     * @return
     */
    private ArticleBehaviorShowDTO getArticleBehaviorShowDTOByArticleId(String key, Long articleId) {

        String json = (String) redisTemplate.opsForHash().get(key, articleId + "");
        if (json == null) {
            return new ArticleBehaviorShowDTO();
        }
        ArticleBehaviorShowDTO behaviorShowDTO = JsonUtils.toBean(json, ArticleBehaviorShowDTO.class);
        if (behaviorShowDTO == null) {
            return new ArticleBehaviorShowDTO();
        }
        return behaviorShowDTO;
    }

    /**
     * 新增或删除点赞信息
     *
     * @param dto
     */
    private void saveOrDeleteLike(LikesBehaviorDto dto, Integer userId) {
        String key = ArticleBehaviorRedisPrefixConstants.BEHAVIOR_LIKE_PREFIX + ":" + userId;
        // 如果是新增点赞
        if (dto.getOperation() == 0) {
            redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JsonUtils.toString(dto));
            // 删除 不喜欢的信息
            redisTemplate.opsForHash().delete(key, dto.getArticleId() + "");
        } else if (dto.getOperation() == 1) {
            redisTemplate.opsForHash().delete(key, dto.getArticleId() + "");
        } else {
            log.error("用户是否点赞参数不合法 LikesBehaviorDto: {}", dto);
        }
    }


    /**
     * 保存或更新UnLike回显信息
     *
     * @param dto
     */
    private void saveOrUpdateUnLikeShow(UnLikesBehaviorDto dto, Integer userId) {
        String key = ArticleBehaviorRedisPrefixConstants.BEHAVIOR_SHOW_PREFIX + ":" + userId;
        String json = (String) redisTemplate.opsForHash().get(key, dto.getArticleId() + "");

        // 如果Redis中数据不为空, 则进行修改
        if (StringUtils.isNotEmpty(json) && JsonUtils.toBean(json, ArticleBehaviorShowDTO.class) != null) {
            ArticleBehaviorShowDTO behaviorShowDTO = JsonUtils.toBean(json, ArticleBehaviorShowDTO.class);

            // 如果是不喜欢,需要同时设置点赞为false
            if (dto.getType() == 0) {
                behaviorShowDTO.setIslike(false);
                behaviorShowDTO.setIsunlike(true);
                //TODO: 算分
            } else if (dto.getType() == 1) {
                behaviorShowDTO.setIsunlike(false);
            }
            redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JSON.toJSONString(behaviorShowDTO));
        }
        // 如果Redis中的数据为空,则进行新增.
        ArticleBehaviorShowDTO behaviorShowDTO = new ArticleBehaviorShowDTO();
        behaviorShowDTO.setIsunlike(dto.getType() == 0);
        redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JSON.toJSONString(behaviorShowDTO));
    }


    /**
     * 保存或删除UnLike信息
     *
     * @param dto
     */
    private void saveOrDeleteUnLike(UnLikesBehaviorDto dto) {
        // 设置key
        String key = ArticleBehaviorRedisPrefixConstants.BEHAVIOR_UNLIKE_PREFIX + ":" + UserThreadLocalUtils.getUserId();
        // 判断用户当前操作是设置为不喜欢还是取消不喜欢   如果是设置不喜欢,则新增
        if (dto.getType() == 0) {
            redisTemplate.opsForHash().put(key, dto.getArticleId() + "", JSON.toJSONString(dto));
            // 删除 喜欢信息
            redisTemplate.opsForHash().delete(key, dto.getArticleId() + "");
        }
        // 如果是取消不喜欢,则删除
        if (dto.getType() == 1) {
            redisTemplate.opsForHash().delete(key, dto.getArticleId() + "");
        }
    }
}
